package etxt2db.annotators;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.text.ParseException;
import java.util.Iterator;
import java.util.List;

import com.aliasi.chunk.CharLmHmmChunker;
import com.aliasi.chunk.Chunk;
import com.aliasi.chunk.Chunking;
import com.aliasi.chunk.HmmChunker;
import com.aliasi.hmm.HmmCharLmEstimator;
import com.aliasi.tokenizer.IndoEuropeanTokenizerFactory;
import com.aliasi.tokenizer.TokenizerFactory;
import com.aliasi.util.AbstractExternalizable;

import edu.cmu.minorthird.text.BasicTextLabels;
import edu.cmu.minorthird.text.MonotonicTextLabels;
import edu.cmu.minorthird.text.Span;
import edu.cmu.minorthird.text.TextLabels;
import etxt2db.api.ClassificationModel;
import etxt2db.corpus.CompleteTextLabels;
import etxt2db.corpus.LingpipeHMMTrainer;

public class LingpipeHMMClassificationModel  extends ClassificationModel implements Serializable {

	private static final long serialVersionUID = -5498084686775961071L;
	private HmmChunker chunkerEstimator;
	static final int MAX_N_GRAM = 8;
	static final int NUM_CHARS = 256;
	static final double LM_INTERPOLATION = MAX_N_GRAM; // default behavior
	
	@SuppressWarnings("deprecation")
	public LingpipeHMMClassificationModel(TextLabels file, List<String> attribute) throws IOException, ParseException {
		TokenizerFactory factory = IndoEuropeanTokenizerFactory.FACTORY;
        HmmCharLmEstimator hmmEstimator
          	= new HmmCharLmEstimator(MAX_N_GRAM,NUM_CHARS,LM_INTERPOLATION);
        CharLmHmmChunker chunker = new CharLmHmmChunker(factory,hmmEstimator);
        
        LingpipeHMMTrainer parser = new LingpipeHMMTrainer(attribute);
        parser.setHandler(chunker);
        
        parser.parse(file);

        File modelFile = File.createTempFile("HMMTemp", "ann");
        AbstractExternalizable.compileTo(chunker,modelFile);
        
        try {
			chunkerEstimator
			= (HmmChunker)
			AbstractExternalizable.readObject(modelFile);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

    }
	
	@Override
	public void annotate(MonotonicTextLabels arg0) {
		//We need an iterator to navigate through the Document Spans
		Iterator<Span> iter = arg0.getTextBase().documentSpanIterator();
		while(iter.hasNext()){
			Span span = iter.next();
			//The chunking interface of Lingpipe uses strings, so we need to
			//convert our documents to strings.
			Chunking chunking = chunkerEstimator.chunk(span.asString());
			for (Chunk chunk : chunking.chunkSet()) {
				//Each chunk gives us the start and end of the span we want to
				//annotate
	            int start = chunk.start();
	            int end = chunk.end();
	            
	            //Luckily it is what we want in the Span interface
	            Span newSpan=span.charIndexProperSubSpan(span.getLoChar()+start+1,span.getLoChar()+end);
	            //We add a new Span to the TexLabels
				arg0.addToType(newSpan,chunk.type());
	        }
		}
	}

	@Override
	public TextLabels annotatedCopy(TextLabels arg0) {
		//Just create a new TextLabels (copy) before annotate
		CompleteTextLabels copy = new CompleteTextLabels(arg0.getTextBase());
		annotate(copy);
		//Return the new TextLabels
		return copy;
	}

	@Override
	public String explainAnnotation(TextLabels arg0, Span arg1) {
		//Not important in this work... but necessary to implement the interface
		return "";
	}
}
